﻿<!DOCTYPE html>
<html class="theme theme-white">
<head>
<meta charset="utf-8">
<title>设计模式</title>
<link href="https://www.zybuluo.com/static/assets/template-theme-white.css" rel="stylesheet" media="screen">
<style type="text/css">

#wmd-preview h1  {
    color: #0077bb; /* 将标题改为蓝色 */
}</style>
</head>
<body class="theme theme-white">
<div id="wmd-preview" class="wmd-preview wmd-preview-full-reader"><div class="md-section-divider"></div><div class="md-section-divider"></div><h1 data-anchor-id="45la" id="设计模式">设计模式</h1><p data-anchor-id="rlrt"><code>Java面试题</code> <code>设计模式</code></p><hr><div class="md-section-divider"></div><h3 data-anchor-id="43ty" id="简述一下你了解的设计模式">简述一下你了解的设计模式。</h3><p data-anchor-id="omn6">答：所谓设计模式，就是一套被反复使用的代码设计经验的总结（情境中一个问题经过证实的一个解决方案）。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。  <br>
在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中给出了三类（创建型[对类的实例化过程的抽象化]、结构型[描述如何将类或对象结合在一起形成更大的结构]、行为型[对在不同的对象之间划分责任和算法的抽象化]）共23种设计模式，包括：Abstract Factory（抽象工厂模式），Builder（建造者模式），Factory Method（工厂方法模式），Prototype（原始模型模式），Singleton（单例模式）；Facade（门面模式），Adapter（适配器模式），Bridge（桥梁模式），Composite（合成模式），Decorator（装饰模式），Flyweight（享元模式），Proxy（代理模式）；Command（命令模式），Interpreter（解释器模式），Visitor（访问者模式），Iterator（迭代子模式），Mediator（调停者模式），Memento（备忘录模式），Observer（观察者模式），State（状态模式），Strategy（策略模式），Template Method（模板方法模式）， Chain Of Responsibility（责任链模式）。  <br>
面试被问到关于设计模式的知识时，可以拣最常用的作答，例如：  <br>
- 工厂模式：工厂类可以根据条件生成不同的子类实例，这些子类有一个公共的抽象父类并且实现了相同的方法，但是这些方法针对不同的数据进行了不同的操作（多态方法）。当得到子类的实例后，开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。  <br>
- 代理模式：给一个对象提供一个代理对象，并由代理对象控制原对象的引用。实际开发中，按照使用目的的不同，代理可以分为：远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。  <br>
- 适配器模式：把一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口不匹配而无法在一起使用的类能够一起工作。  <br>
- 模板方法模式：提供一个抽象类，将部分逻辑以具体方法或构造器的形式实现，然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法（多态实现），从而实现不同的业务逻辑。  <br>
除此之外，还可以讲讲上面提到的门面模式、桥梁模式、单例模式、装潢模式（Collections工具类和I/O系统中都使用装潢模式）等，反正基本原则就是拣自己最熟悉的、用得最多的作答，以免言多必失。</p><div class="md-section-divider"></div><h3 data-anchor-id="4cci" id="写一个单例类">写一个单例类</h3><p data-anchor-id="byd0">答：单例模式主要作用是保证在 Java 应用程序中，一个类只有一个实例存在。下面给出两种不同形式的单例：</p><p data-anchor-id="xleg">第一种形式：饿汉式单例</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="xv0h"><ol class="linenums"><li class="L0"><code class="language-java"><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span></code></li><li class="L1"><code class="language-java"><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">(){}</span><span class="pln">  </span></code></li><li class="L2"><code class="language-java"><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> instance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">();</span><span class="pln">  </span></code></li><li class="L3"><code class="language-java"><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> getInstance</span><span class="pun">(){</span><span class="pln">  </span></code></li><li class="L4"><code class="language-java"><span class="pln">        </span><span class="kwd">return</span><span class="pln"> instance</span><span class="pun">;</span><span class="pln">  </span></code></li><li class="L5"><code class="language-java"><span class="pln">    </span><span class="pun">}</span><span class="pln">  </span></code></li><li class="L6"><code class="language-java"><span class="pun">}</span><span class="pln">  </span></code></li></ol></pre><p data-anchor-id="8i9y">第二种形式：懒汉式单例</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="sd64"><ol class="linenums"><li class="L0"><code><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span></code></li><li class="L1"><code><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> instance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">  </span></code></li><li class="L2"><code><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">  </span></code></li><li class="L3"><code><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">synchronized</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> getInstance</span><span class="pun">(){</span><span class="pln">  </span></code></li><li class="L4"><code><span class="pln">        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">instance</span><span class="pun">==</span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> instance</span><span class="pun">＝</span><span class="pln">newSingleton</span><span class="pun">();</span><span class="pln">  </span></code></li><li class="L5"><code><span class="pln">        </span><span class="kwd">return</span><span class="pln"> instance</span><span class="pun">;</span><span class="pln">  </span></code></li><li class="L6"><code><span class="pln">    </span><span class="pun">}</span><span class="pln">  </span></code></li><li class="L7"><code><span class="pun">}</span><span class="pln">  </span></code></li></ol></pre><p data-anchor-id="zr3o">单例的特点：外界无法通过构造器来创建对象，该类必须提供一个静态方法向外界提供该类的唯一实例。</p><p data-anchor-id="2va7">【补充】用 Java 进行服务器端编程时，使用单例模式的机会还是很多的，服务器上的资源都是很宝贵的，对于那些无状态的对象其实都可以单例化或者静态化（在内存中仅有唯一拷贝），如果使用了 Spring 这样的框架来进行对象托管，Spring 的 IoC 容器在默认情况下对所有托管对象都是进行了单例化处理的。</p><div class="md-section-divider"></div><h3 data-anchor-id="8abq" id="说说你所熟悉或听说过的设计模式以及你对设计模式的看法">说说你所熟悉或听说过的设计模式以及你对设计模式的看法。</h3><p data-anchor-id="2ush">答：在 GoF 的《Design Patterns: Elements of Reusable Object-Oriented Software》中给出了三类（创建型[对类的实例化过程的抽象化]、结构型[描述如何将类或对象结合在一起形成更大的结构]、行为型[对在不同的对象之间划分责任和算法的抽象化]）共 23 种设计模式，包括：Abstract Factory（抽象工厂模式），Builder（建造者模式），Factory Method（工厂方法模式），Prototype（原始模型模式），Singleton（单例模式）；Facade（门面模式），Adapter（适配器模式），Bridge（桥梁模式），Composite（合成模式），Decorator（装饰模式），Flyweight（享元模式），Proxy（代理模式）；Command（命令模式），Interpreter（解释器模式），Visitor（访问者模式），Iterator（迭代子模式），Mediator（调停者模式），Memento（备忘录模式），Observer（观察者模式），State（状态模式），Strategy（策略模式），Template Method（模板方法模式）， Chain Of Responsibility（责任链模式）。</p><p data-anchor-id="blg8">所谓设计模式，就是一套被反复使用的代码设计经验的总结（情境中一个问题经过证实的一个解决方案）。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。</p><div class="md-section-divider"></div><h3 data-anchor-id="h1n5" id="你在开发中都用到了那些设计模式用在什么场合">你在开发中都用到了那些设计模式？用在什么场合？</h3><p data-anchor-id="k11z">答：面试被问到关于设计模式的知识时，可以拣最常用的作答，例如：</p><p data-anchor-id="ycrw">1)工厂模式：工厂类可以根据条件生成不同的子类实例，这些子类有一个公共的抽象父类并且实现了相同的方法，但是这些方法针对不同的数据进行了不同的操作（多态方法）。当得到子类的实例后，开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。</p><p data-anchor-id="7g71">2)代理模式：给一个对象提供一个代理对象，并由代理对象控制原对象的引用。实际开发中，按照使用目的的不同，代理可以分为：远程代理、虚拟代理、保护代理、Cache 代理、防火墙代理、同步化代理、智能引用代理。</p><p data-anchor-id="fayt">3)适配器模式：把一个类的接口变换成客户端所期待的另一种接口，从而使原本因接口不匹配而无法在一起使用的类能够一起工作。</p><p data-anchor-id="syki">4)模板方法模式：提供一个抽象类，将部分逻辑以具体方法或构造器的形式实现，然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法（多态实现），从而实现不同的业务逻辑。</p><p data-anchor-id="7ovt">除此之外，还可以讲讲上面提到的门面模式、桥梁模式、单例模式、装潢模式（Collections 工具类里面的 synchronizedXXX 方法把一个线程不安全的容器变成线程安全容器就是对装潢模式的应用，而 Java IO 里面的过滤流（有的翻译成处理流）也是应用装潢模式的经典例子）等，反正原则就是拣自己最熟悉的用得最多的作答，以免言多必失。</p><div class="md-section-divider"></div><h3 data-anchor-id="t3my" id="编程题-写一个singleton出来">编程题: 写一个Singleton出来</h3><p data-anchor-id="8x10">Singleton 模式主要作用是保证在 Java 应用程序中，一个类 Class 只有一个实例存在。 一般 Singleton 模式通常有几种种形式:</p><p data-anchor-id="zv2b">第一种形式: 定义一个类，它的构造函数为 private的，它有一个 static 的 private 的该类变量，在类初始化时实例话，通过一个 public 的 getInstance 方法获取对它的引用,继而调用其中的方法。</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="kwg9"><ol class="linenums"><li class="L0"><code><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L1"><code><span class="kwd">private</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">(){}</span></code></li><li class="L2"><code><span class="pln">　　 </span><span class="com">//在自己内部定义自己一个实例，是不是很奇怪？</span></code></li><li class="L3"><code><span class="pln">　　 </span><span class="com">//注意这是private 只供内部调用</span></code></li><li class="L4"><code><span class="pln">　　 </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> instance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">();</span></code></li><li class="L5"><code><span class="pln">　　 </span><span class="com">//这里提供了一个供外部访问本class的静态方法，可以直接访问　　</span></code></li><li class="L6"><code><span class="pln">　　 </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> getInstance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L7"><code><span class="pln">　　　　 </span><span class="kwd">return</span><span class="pln"> instance</span><span class="pun">;</span><span class="pln"> 　　</span></code></li><li class="L8"><code><span class="pln">　　 </span><span class="pun">}</span><span class="pln"> </span></code></li><li class="L9"><code><span class="pun">}</span><span class="pln"> </span></code></li></ol></pre><p data-anchor-id="r6ng">第二种形式: </p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="l24y"><ol class="linenums"><li class="L0"><code><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span></code></li><li class="L1"><code><span class="pln">　　</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> instance </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></code></li><li class="L2"><code><span class="pln">　　</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">synchronized</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pln"> getInstance</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L3"><code><span class="pln">　　</span><span class="com">//这个方法比上面有所改进，不用每次都进行生成对象，只是第一次　　　 　</span></code></li><li class="L4"><code><span class="pln">　　</span><span class="com">//使用时生成实例，提高了效率！</span></code></li><li class="L5"><code><span class="pln">　　</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">instance</span><span class="pun">==</span><span class="kwd">null</span><span class="pun">)</span></code></li><li class="L6"><code><span class="pln">　　　　instance</span><span class="pun">＝</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Singleton</span><span class="pun">();</span></code></li><li class="L7"><code><span class="kwd">return</span><span class="pln"> instance</span><span class="pun">;</span><span class="pln"> 　　</span><span class="pun">}</span><span class="pln"> </span></code></li><li class="L8"><code><span class="pun">}</span><span class="pln"> </span></code></li></ol></pre><p data-anchor-id="5fwt">其他形式:</p><p data-anchor-id="q1nt">定义一个类，它的构造函数为 private 的，所有方法为 static 的。</p><p data-anchor-id="q6ll">一般认为第一种形式要更加安全些</p><div class="md-section-divider"></div><h3 data-anchor-id="m6ax" id="结束">结束</h3></div>
</body>
</html>